home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / pmake / prefix / printf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-15  |  30.9 KB  |  1,332 lines

  1. /***********************************************************************
  2.  *
  3.  * PROJECT:      PMake
  4.  * MODULE:      Prefix -- Formatted Output
  5.  * FILE:      printf.c
  6.  *
  7.  * AUTHOR:        Adam de Boor: Aug 11, 1989
  8.  *
  9.  * ROUTINES:
  10.  *    Name              Description
  11.  *    ----              -----------
  12.  *    printf                Print to stdout
  13.  *    fprintf                Print to a stream
  14.  *    sprintf                Print to a string
  15.  *    vprintf                Print varargs to stdout
  16.  *    vfprintf            Workhorse -- print varargs to a stream
  17.  *    vsprintf            Print varargs to a string.
  18.  *
  19.  * REVISION HISTORY:
  20.  *    Date      Name        Description
  21.  *    ----      ----        -----------
  22.  *    8/11/89      ardeb        Initial version
  23.  *
  24.  * DESCRIPTION:
  25.  *    This thing is necessary so prefix can work with gcc on a Sparc.
  26.  *    I've not found a way to use vprintf and GCC's varargs, so I'm
  27.  *    giving up and snarfing this from another project of mine.
  28.  *
  29.  *     All these functions are based around a modified vfprintf written
  30.  *    by people on the Sprite project at UC Berkeley:
  31.  *
  32.  *    Copyright 1988 Regents of the University of California
  33.  *    Permission to use, copy, modify, and distribute this
  34.  *    software and its documentation for any purpose and without
  35.  *    fee is hereby granted, provided that the above copyright
  36.  *    notice appear in all copies.  The University of California
  37.  *    makes no representations about the suitability of this
  38.  *    software for any purpose.  It is provided "as is" without
  39.  *    express or implied warranty.
  40.  *
  41.  ***********************************************************************/
  42. #ifndef lint
  43. static char *rcsid =
  44. "$Id: printf.c,v 1.2 89/11/14 17:18:22 adam Exp $";
  45. #endif lint
  46.  
  47. #include <ctype.h>
  48. #include <stdio.h>
  49. #include <strings.h>
  50. #include <varargs.h>
  51.  
  52. #ifndef TRUE
  53. #define TRUE 1
  54. #endif
  55. #ifndef FALSE
  56. #define FALSE 0
  57. #endif
  58.  
  59. /*
  60.  * The following defines the size of buffer needed to hold the ASCII
  61.  * digits for the largest floating-point number and the largest integer.
  62.  */
  63.  
  64. #define CVT_DBL_BUF_SIZE 320
  65. #define CVT_INT_BUF_SIZE 33
  66.  
  67. /*
  68.  *----------------------------------------------------------------------
  69.  *
  70.  * CvtUtoA --
  71.  *
  72.  *    Convert a number from internal form to a sequence of
  73.  *    ASCII digits.
  74.  *
  75.  * Results:
  76.  *    The return value is a pointer to the ASCII digits representing
  77.  *    i, and *lengthPtr will be filled in with the number of digits
  78.  *    stored at the location pointed to by the return value.  The
  79.  *    return value points somewhere inside buf, but not necessarily
  80.  *    to the beginning.  Note:  the digits are left null-terminated.
  81.  *
  82.  * Side effects:
  83.  *    None.
  84.  *
  85.  *----------------------------------------------------------------------
  86.  */
  87.  
  88. static char *
  89. CvtUtoA(i, base, buf, lengthPtr)
  90.     register unsigned i;    /* Value to convert. */
  91.     register int base;        /* Base for conversion.  Shouldn't be
  92.                  * larger than 36.  2, 8, and 16
  93.                  * execute fastest.
  94.                  */
  95.     register char *buf;        /* Buffer to use to hold converted string.
  96.                  * Must hold at least CVT_INT_BUF_SIZE bytes. */
  97.     int *lengthPtr;        /* Number of digits is stored here. */
  98. {
  99.     register char *p;
  100.  
  101.     /*
  102.      * Handle a zero value specially.
  103.      */
  104.  
  105.     if (i == 0) {
  106.     buf[0] = '0';
  107.     buf[1] = 0;
  108.     *lengthPtr = 1;
  109.     return buf;
  110.     }
  111.  
  112.     /*
  113.      * Build the string backwards from the end of the result array.
  114.      */
  115.  
  116.     p = &buf[CVT_INT_BUF_SIZE-1];
  117.     *p = 0;
  118.  
  119.     switch (base) {
  120.  
  121.     case 2:
  122.         while (i != 0) {
  123.         p -= 1;
  124.         *p = '0' + (i & 01);
  125.         i >>= 1;
  126.         }
  127.         break;
  128.     
  129.     case 8:
  130.         while (i != 0) {
  131.         p -= 1;
  132.         *p = '0' + (i & 07);
  133.         i >>= 3;
  134.         }
  135.         break;
  136.     
  137.     case 16:
  138.         while (i !=0) {
  139.         p -= 1;
  140.         *p = '0' + (i & 0xf);
  141.         if (*p > '9') {
  142.             *p += 'a' - '9' - 1;
  143.         }
  144.         i >>= 4;
  145.         }
  146.         break;
  147.     
  148.     default:
  149.         while (i != 0) {
  150.         p -= 1;
  151.         *p = '0' + (i % base);
  152.         if (*p > '9') {
  153.             *p += 'a' - '9' - 1;
  154.         }
  155.         i /= base;
  156.         }
  157.         break;
  158.     }
  159.  
  160.     *lengthPtr = (&buf[CVT_INT_BUF_SIZE-1] - p);
  161.     return p;
  162. }
  163.  
  164. /*
  165.  *----------------------------------------------------------------------
  166.  *
  167.  * CvtFtoA --
  168.  *
  169.  *    This procedure converts a double-precision floating-point
  170.  *    number to a string of ASCII digits.
  171.  *
  172.  * Results:
  173.  *    The characters at buf are modified to hold up to numDigits ASCII
  174.  *    characters, followed by a null character.  The digits represent
  175.  *    the most significant numDigits digits of value, with the lowest
  176.  *    digit rounded.  The value at *pointPtr is modified to hold
  177.  *    the number of characters in buf that precede the decimal point.
  178.  *    A negative value of *pointPtr means zeroes must be inserted
  179.  *    between the point and buf[0].  If value is negative, *signPtr
  180.  *    is set to TRUE;    otherwise it is set to FALSE.  The return value
  181.  *    is the number of digits stored in buf, which is either:
  182.  *    (a) numDigits (if the number is so huge that all numDigits places are
  183.  *        used before getting to the right precision level, or if
  184.  *        afterPoint is -1)
  185.  *    (b) afterPoint + *pointPtr (the normal case if afterPoint isn't -1)
  186.  *    If there were no significant digits within the specified precision,
  187.  *    then *pointPtr gets set to -afterPoint and 0 is returned.
  188.  *
  189.  * Side effects:
  190.  *    None.
  191.  *
  192.  *----------------------------------------------------------------------
  193.  */
  194.  
  195. static int
  196. CvtFtoA(value, numDigits, afterPoint, pointPtr, signPtr, buf, fpError)
  197.     double value;        /* Value to be converted. */
  198.     int numDigits;        /* Maximum number of significant digits
  199.                  * to generate in result. */
  200.     int afterPoint;        /* Maximum number of digits to generate
  201.                  * after the decimal point.  If -1, then
  202.                  * there there is no limit. */
  203.     int *pointPtr;        /* Will be filled in with position of
  204.                  * decimal point (number of digits before
  205.                  * decimal point). */
  206.     int *signPtr;        /* Modified to indicate whether or not
  207.                  * value was negative. */
  208.     char *buf;            /* Place to store ASCII digits.  Must hold
  209.                  * at least numDigits+1 bytes. */
  210.     int *fpError;               /* pointer to flag that is set if the number
  211.                                    is not a valid number. */
  212.  
  213. {
  214.     extern double modf();
  215.     register char *p;
  216.     double fraction, intPart;
  217.     int i, numDigits2;
  218.     char tmpBuf[CVT_DBL_BUF_SIZE];
  219.                 /* Large enough to hold largest possible
  220.                  * floating-point number.
  221.                  */
  222.  
  223.     /*
  224.      * Make sure the value is a valid number
  225.      */
  226.     if (isinf(value)) {
  227.     /*
  228.      * Set the error flag so the invoking function will know
  229.      * that something is wrong.
  230.      */
  231.     *fpError = TRUE;
  232.     strcpy(buf, "(INFINITY)");
  233.     return sizeof("(INFINITY)") - 1;
  234.     }
  235.     if (isnan(value)) {
  236.     *fpError = TRUE;
  237.     strcpy(buf, "(NaN)");
  238.     return sizeof("(NaN)") - 1;
  239.     }
  240.     *fpError = FALSE;
  241.  
  242.     /*
  243.      * Take care of the sign.
  244.      */
  245.  
  246.     if (value < 0.0) {
  247.     *signPtr = TRUE;
  248.     value = -value;
  249.     } else {
  250.     *signPtr = FALSE;
  251.     }
  252.  
  253.     /*
  254.      * Divide value into an integer and a fractional component.  Convert
  255.      * the integer to ASCII in a temporary buffer, then move the characters
  256.      * to the real buffer (since we're converting from the bottom up,
  257.      * we won't know the highest-order digit until last).
  258.      */
  259.  
  260.     fraction = modf(value, &intPart);
  261.     *pointPtr = 0;
  262.     for (p = &tmpBuf[CVT_DBL_BUF_SIZE-1]; intPart != 0; p -= 1) {
  263.     double tmp;
  264.     char digit;
  265.  
  266.     tmp = modf(intPart/10.0, &intPart);
  267.  
  268.     digit = (tmp * 10.0) + .2;
  269.     *p = digit + '0';
  270.     *pointPtr += 1;
  271.     }
  272.     p++;
  273.     for (i = 0; (i <= numDigits) && (p <= &tmpBuf[CVT_DBL_BUF_SIZE-1]);
  274.         i++, p++) {
  275.     buf[i] = *p;
  276.     }
  277.  
  278.     /*
  279.      * If the value was zero, put an initial zero in the buffer
  280.      * before the decimal point.
  281.      */
  282.     
  283.     if (value == 0.0) {
  284.     buf[0] = '0';
  285.     i = 1;
  286.     *pointPtr = 1;
  287.     }
  288.  
  289.     /*
  290.      * Now handle the fractional part that's left.  Repeatedly multiply
  291.      * by 10 to get the next digit.  At the beginning, the value may be
  292.      * very small, so do repeated multiplications until we get to a
  293.      * significant digit.
  294.      */
  295.     
  296.     if ((i == 0) && (fraction > 0)) {
  297.     while (fraction < .1) {
  298.         fraction *= 10.0;
  299.         *pointPtr -= 1;
  300.     };
  301.     }
  302.  
  303.     /*
  304.      * Compute how many total digits we should generate, taking into
  305.      * account both numDigits and afterPoint.  Then generate the digits.
  306.      */
  307.     
  308.     numDigits2 = afterPoint + *pointPtr;
  309.     if ((afterPoint < 0) || (numDigits2 > numDigits)) {
  310.     numDigits2 = numDigits;
  311.     }
  312.     
  313.     for ( ; i <= numDigits2; i++) {
  314.     double tmp;
  315.     char digit;
  316.  
  317.     fraction = modf(fraction*10.0, &tmp);
  318.  
  319.     digit = tmp;
  320.     buf[i] = digit + '0';
  321.     }
  322.  
  323.     /*
  324.      * The code above actually computed one more digit than is really
  325.      * needed.  Use it to round the low-order significant digit, if
  326.      * necessary.  This could cause rounding to propagate all the way
  327.      * back through the number.
  328.      */
  329.     
  330.     if ((numDigits2 >= 0) && (buf[numDigits2] >= '5')) {
  331.     for (i = numDigits2-1; ; i--) {
  332.         if (i < 0) {
  333.         int j;
  334.  
  335.         /*
  336.          * Must slide the entire buffer down one slot to make
  337.          * room for a leading 1 in the buffer.  Careful: if we've
  338.          * already got numDigits digits, must drop the last one to
  339.          * add the 1.
  340.          */
  341.  
  342.         for (j = numDigits2; j > 0; j--) {
  343.             buf[j] = buf[j-1];
  344.         }
  345.         if (numDigits2 < numDigits) {
  346.             numDigits2++;
  347.         }
  348.         (*pointPtr)++;
  349.         buf[0] = '1';
  350.         break;
  351.         }
  352.  
  353.         buf[i] += 1;
  354.         if (buf[i] <= '9') {
  355.         break;
  356.         }
  357.         buf[i] = '0';
  358.     }
  359.     }
  360.  
  361.     if (numDigits2 <= 0) {
  362.     numDigits2 = 0;
  363.     *pointPtr = -afterPoint;
  364.     }
  365.     buf[numDigits2] = 0;
  366.     return numDigits2;
  367. }
  368.  
  369. /*
  370.  * The table below is used to convert from ASCII digits to a
  371.  * numerical equivalent.  It maps from '0' through 'z' to integers
  372.  * (100 for non-digit characters).
  373.  */
  374.  
  375. #ifndef __STDC__
  376. #define const
  377. #endif
  378.  
  379. static const char cvtIn[] = {
  380.     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,        /* '0' - '9' */
  381.     100, 100, 100, 100, 100, 100, 100,        /* punctuation */
  382.     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,    /* 'A' - 'Z' */
  383.     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  384.     30, 31, 32, 33, 34, 35,
  385.     100, 100, 100, 100, 100, 100,        /* punctuation */
  386.     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,    /* 'a' - 'z' */
  387.     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  388.     30, 31, 32, 33, 34, 35};
  389.  
  390. /*
  391.  *----------------------------------------------------------------------
  392.  *
  393.  * strtoul --
  394.  *
  395.  *    Convert an ASCII string into an integer.
  396.  *
  397.  * Results:
  398.  *    The return value is the integer equivalent of string.  If endPtr
  399.  *    is non-NULL, then *endPtr is filled in with the character
  400.  *    after the last one that was part of the integer.  If string
  401.  *    doesn't contain a valid integer value, then zero is returned
  402.  *    and *endPtr is set to string.
  403.  *
  404.  * Side effects:
  405.  *    None.
  406.  *
  407.  *----------------------------------------------------------------------
  408.  */
  409.  
  410. unsigned long int
  411. strtoul(string, endPtr, base)
  412.     char *string;        /* String of ASCII digits, possibly
  413.                  * preceded by white space.  For bases
  414.                  * greater than 10, either lower- or
  415.                  * upper-case digits may be used.
  416.                  */
  417.     char **endPtr;        /* Where to store address of terminating
  418.                  * character, or NULL. */
  419.     int base;            /* Base for conversion.  Must be less
  420.                  * than 37.  If 0, then the base is chosen
  421.                  * from the leading characters of string:
  422.                  * "0x" means hex, "0" means octal, anything
  423.                  * else means decimal.
  424.                  */
  425. {
  426.     register char *p;
  427.     register unsigned long int result = 0;
  428.     register unsigned digit;
  429.     int anyDigits = FALSE;
  430.  
  431.     /*
  432.      * Skip any leading blanks.
  433.      */
  434.  
  435.     p = string;
  436.     while (isspace(*p)) {
  437.     p += 1;
  438.     }
  439.  
  440.     /*
  441.      * If no base was provided, pick one from the leading characters
  442.      * of the string.
  443.      */
  444.     
  445.     if (base == 0)
  446.     {
  447.     if (*p == '0') {
  448.         p += 1;
  449.         if (*p == 'x') {
  450.         p += 1;
  451.         base = 16;
  452.         } else {
  453.  
  454.         /*
  455.          * Must set anyDigits here, otherwise "0" produces a
  456.          * "no digits" error.
  457.          */
  458.  
  459.         anyDigits = TRUE;
  460.         base = 8;
  461.         }
  462.     }
  463.     else base = 10;
  464.     } else if (base == 16) {
  465.  
  466.     /*
  467.      * Skip a leading "0x" from hex numbers.
  468.      */
  469.  
  470.     if ((p[0] == '0') && (p[1] == 'x')) {
  471.         p += 2;
  472.     }
  473.     }
  474.  
  475.     /*
  476.      * Sorry this code is so messy, but speed seems important.  Do
  477.      * different things for base 8, 10, 16, and other.
  478.      */
  479.  
  480.     if (base == 8) {
  481.     for ( ; ; p += 1) {
  482.         digit = *p - '0';
  483.         if (digit > 7) {
  484.         break;
  485.         }
  486.         result = (result << 3) + digit;
  487.         anyDigits = TRUE;
  488.     }
  489.     } else if (base == 10) {
  490.     for ( ; ; p += 1) {
  491.         digit = *p - '0';
  492.         if (digit > 9) {
  493.         break;
  494.         }
  495.         result = (10*result) + digit;
  496.         anyDigits = TRUE;
  497.     }
  498.     } else if (base == 16) {
  499.     for ( ; ; p += 1) {
  500.         digit = *p - '0';
  501.         if (digit > ('z' - '0')) {
  502.         break;
  503.         }
  504.         digit = cvtIn[digit];
  505.         if (digit > 15) {
  506.         break;
  507.         }
  508.         result = (result << 4) + digit;
  509.         anyDigits = TRUE;
  510.     }
  511.     } else {
  512.     for ( ; ; p += 1) {
  513.         digit = *p - '0';
  514.         if (digit > ('z' - '0')) {
  515.         break;
  516.         }
  517.         digit = cvtIn[digit];
  518.         if (digit >= base) {
  519.         break;
  520.         }
  521.         result = result*base + digit;
  522.         anyDigits = TRUE;
  523.     }
  524.     }
  525.  
  526.     /*
  527.      * See if there were any digits at all.
  528.      */
  529.  
  530.     if (!anyDigits) {
  531.     p = string;
  532.     }
  533.  
  534.     if (endPtr != NULL) {
  535.     *endPtr = p;
  536.     }
  537.  
  538.     return result;
  539. }
  540.  
  541. /*
  542.  *----------------------------------------------------------------------
  543.  *
  544.  * vfprintf --
  545.  *
  546.  *    This utility routine does all of the real work of printing
  547.  *    formatted information.  It is called by printf, fprintf,
  548.  *    sprintf, vprintf, and vsprintf.
  549.  *
  550.  * Results:
  551.  *    The return value is the total number of characters printed.
  552.  *
  553.  * Side effects:
  554.  *    Information is output on stream.  See the manual page entry
  555.  *    for printf for details.
  556.  *
  557.  *----------------------------------------------------------------------
  558.  */
  559.  
  560. int
  561. vfprintf(stream, format, args)
  562.     register FILE *stream;    /* Where to output formatted results. */
  563.     register char *format;    /* Contains literal text and format control
  564.                  * sequences indicating how args are to be
  565.                  * printed.  See the man page for details. */
  566.     va_list args;        /* Variable number of values to be formatted
  567.                  * and printed. */
  568. {
  569.     int leftAdjust;        /* TRUE means field should be left-adjusted. */
  570.     int minWidth;        /* Minimum width of field. */
  571.     int precision;        /* Precision for field (e.g. digits after
  572.                  * decimal, or string length). */
  573.     int altForm;        /* TRUE means value should be converted to
  574.                  * an alternate form (depends on type of
  575.                  * conversion). */
  576.     register char c;        /* Current character from format string.
  577.                  * Eventually it ends up holding the format
  578.                  * type (e.g. 'd' for decimal). */
  579.     char pad;            /* Pad character. */
  580.     char buf[CVT_DBL_BUF_SIZE+10];
  581.                 /* Buffer used to hold converted numbers
  582.                  * before outputting to stream.  Must be
  583.                  * large enough for floating-point number
  584.                  * plus sign plus "E+XXX + null" */
  585.     char expBuf[CVT_INT_BUF_SIZE];
  586.                 /* Buffer to use for converting exponents. */
  587.     char *prefix;        /* Holds non-numeric stuff that precedes
  588.                  * number, such as "-" or "0x".  This is
  589.                  * kept separate to be sure we add padding
  590.                  * zeroes AFTER the prefix. */
  591.     register char *field;    /* Pointer to converted field. */
  592.     int actualLength;        /* Actual length of converted field. */
  593.     int point;            /* Location of decimal point, for "f" and
  594.                  * "e" conversions. */
  595.     int sign;            /* Also used for "f" and "e" conversions. */
  596.     int i, tmp;
  597.     int charsPrinted = 0;    /* Total number of characters output. */
  598.     char *end;
  599.     int fpError = FALSE;
  600.  
  601.     /*
  602.      * The main loop is to scan through the characters in format.
  603.      * Anything but a '%' is output directly to stream.  A '%'
  604.      * signals the start of a format field;  the formatting information
  605.      * is parsed, the next value from args is formatted and printed,
  606.      * and the loop goes on.
  607.      */
  608.  
  609.     for (c = *format; c != 0; format++, c = *format) {
  610.  
  611.     if (c != '%') {
  612.         putc(c, stream);
  613.         charsPrinted += 1;
  614.         continue;
  615.     }
  616.  
  617.     /*
  618.      * Parse off the format control fields.
  619.      */
  620.  
  621.     leftAdjust    = FALSE;
  622.     pad        = ' ';
  623.     minWidth    = 0;
  624.     precision    = -1;
  625.     altForm        = FALSE;
  626.     prefix        = "";
  627.     actualLength = 0;
  628.  
  629.     format++;  
  630.     c = *format;
  631.     while (TRUE) {
  632.         if (c == '-') {
  633.         leftAdjust = TRUE;
  634.         } else if (c == '0') {
  635.         pad = '0';
  636.         } else if (c == '#') {
  637.         altForm = TRUE;
  638.         } else if (c == '+') {
  639.         prefix = "+";
  640.         actualLength = 1;
  641.         } else {
  642.         break;
  643.         }
  644.         format++;
  645.         c = *format;
  646.     }
  647.     if (isdigit(c)) {
  648.         minWidth = strtoul(format, &end, 10);
  649.         format = end;
  650.         c = *format;
  651.     } else if (c == '*') {
  652.         minWidth = va_arg(args, int);
  653.         format++; 
  654.         c = *format;
  655.     }
  656.     if (c == '.') {
  657.         format++; 
  658.         c = *format;
  659.     }
  660.     if (isdigit(c)) {
  661.         precision = strtoul(format, &end, 10);
  662.         format = end;
  663.         c = *format;
  664.     } else if (c == '*') {
  665.         precision = va_arg(args, int);
  666.         format++; 
  667.         c = *format;
  668.     }
  669.     if (c == 'l') {            /* Ignored for compatibility. */
  670.         format++; 
  671.         c = *format;
  672.     }
  673.  
  674.     /*
  675.      * Take action based on the format type (which is now in c).
  676.      */
  677.  
  678.     field = buf;
  679.     switch (c) {
  680.  
  681.         case 'D':
  682.         case 'd':
  683.         i = va_arg(args, int);
  684.         if (i < 0) {
  685.             prefix = "-";
  686.             i = -i;
  687.             actualLength = 1;
  688.         }
  689.         field = CvtUtoA((unsigned) i, 10, buf, &tmp);
  690.         actualLength += tmp;
  691.         break;
  692.         
  693.         case 'O':
  694.         case 'o':
  695.         i = va_arg(args, int);
  696.         if (altForm && (i != 0)) {
  697.             prefix = "0";
  698.             actualLength = 1;
  699.         }
  700.         field = CvtUtoA((unsigned) i, 8, buf, &tmp);
  701.         actualLength += tmp;
  702.         break;
  703.         
  704.         case 'X':
  705.         case 'x':
  706.         i = va_arg(args, int);
  707.         field = CvtUtoA((unsigned) i, 16, buf, &actualLength);
  708.         if (altForm) {
  709.             char *p;
  710.             if (c == 'X') {
  711.             if (i != 0) {
  712.                 prefix = "0X";
  713.                 actualLength += 2;
  714.             }
  715.             for (p = field; *p != 0; p++) {
  716.                 if (*p >= 'a') {
  717.                 *p += 'A' - 'a';
  718.                 }
  719.             }
  720.             } else if (i != 0) {
  721.             prefix = "0x";
  722.             actualLength += 2;
  723.             }
  724.         }
  725.         break;
  726.         
  727.         case 'U':
  728.         case 'u':
  729.         field = CvtUtoA(va_arg(args, unsigned), 10, buf,
  730.             &actualLength);
  731.         break;
  732.         
  733.         case 's':
  734.         field = va_arg(args, char *);
  735.         if (field == (char *) NULL) {
  736.             field = "(NULL)";
  737.         } 
  738.         actualLength = strlen(field);
  739.         if ((precision >= 0) && (precision < actualLength)) {
  740.             actualLength = precision;
  741.         }
  742.         pad = ' ';
  743.         break;
  744.  
  745.         case 'c':
  746.         buf[0] = va_arg(args, int);
  747.         actualLength = 1;
  748.         pad = ' ';
  749.         break;
  750.  
  751.         case 'F':
  752.         case 'f':
  753.         if (precision < 0) {
  754.             precision = 6;
  755.         } else if (precision > CVT_DBL_BUF_SIZE) {
  756.             precision = CVT_DBL_BUF_SIZE;
  757.         }
  758.  
  759.         /*
  760.          * Just generate the digits and compute the total length
  761.          * here.  The rest of the work will be done when the
  762.          * characters are actually output, below.
  763.          */
  764. #if 0 /*def sun4*/
  765.          /*
  766.           * Varargs is not correctly implemented in gcc version 1.34
  767.           * for the sun4.  This problem should be fixed in the next
  768.           * version of the compiler, and this code can then be
  769.           * deleted.
  770.           */
  771.          {
  772.              union {
  773.                  long i[2];
  774.                  double d;
  775.              } u;
  776.  
  777.              u.i[0] = va_arg(args, long);
  778.              u.i[1] = va_arg(args, long);
  779.  
  780.              actualLength = CvtFtoA(u.d, CVT_DBL_BUF_SIZE,
  781.              precision, &point, &sign, field, &fpError);
  782.          }
  783. #else
  784.         actualLength = CvtFtoA(va_arg(args, double), CVT_DBL_BUF_SIZE,
  785.             precision, &point, &sign, field, &fpError);
  786. #endif
  787.         if (fpError) {
  788.             break;
  789.         }
  790.         if (point <= 0) {
  791.             actualLength += 1 - point;
  792.         }
  793.         if ((precision != 0) || (altForm)) {
  794.             actualLength += 1;
  795.         }
  796.         if (sign) {
  797.             prefix = "-";
  798.             actualLength += 1;
  799.         }
  800.         c = 'f';
  801.         break;
  802.  
  803.         case 'E':
  804.         case 'e':
  805.         if (precision < 0) {
  806.             precision = 6;
  807.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  808.             precision = CVT_DBL_BUF_SIZE-1;
  809.         }
  810. #if 0 /* def sun4*/
  811.          /*
  812.           * Varargs is not correctly implemented in gcc version 1.34
  813.           * for the sun4.  This problem should be fixed in the next
  814.           * version of the compiler, and this code can then be
  815.           * deleted.
  816.           */
  817.          {
  818.              union {
  819.                  long i[2];
  820.                  double d;
  821.              } u;
  822.  
  823.              u.i[0] = va_arg(args, long);
  824.              u.i[1] = va_arg(args, long);
  825.  
  826.              actualLength = CvtFtoA(u.d, precision+1, -1,
  827.              &point, &sign, &buf[1], &fpError);
  828.          }
  829. #else
  830.         actualLength = CvtFtoA(va_arg(args, double), precision+1, -1,
  831.             &point, &sign, &buf[1], &fpError);
  832. #endif
  833.         if (fpError) {
  834.             break;
  835.         }
  836.         eFromG:
  837.  
  838.         /*
  839.          * Insert a decimal point after the first digit of the number.
  840.          * If no digits after decimal point, then don't print decimal
  841.          * unless in altForm.
  842.          */
  843.  
  844.         buf[0] = buf[1];
  845.         buf[1] = '.';
  846.         if ((precision != 0) || (altForm)) {
  847.             field = buf + precision + 2;
  848.         } else {
  849.             field = &buf[1];
  850.         }
  851.  
  852.         /*
  853.          * Convert the exponent.
  854.          */
  855.         
  856.         *field = c;
  857.             field++;
  858.         point--;    /* One digit before decimal point. */
  859.         if (point < 0) {
  860.             *field = '-';
  861.             point = -point;
  862.         } else {
  863.             *field = '+';
  864.         }
  865.         field++;
  866.         if (point < 10) {
  867.             *field = '0';
  868.             field++;
  869.         }
  870.         strcpy(field, CvtUtoA((unsigned) point, 10, expBuf, &i));
  871.         actualLength = (field - buf) + i;
  872.         field = buf;
  873.         if (sign) {
  874.             prefix = "-";
  875.             actualLength += 1;
  876.         }
  877.         break;
  878.  
  879.         case 'G':
  880.         case 'g': {
  881.         int eLength, fLength;
  882.  
  883.         if (precision < 0) {
  884.             precision = 6;
  885.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  886.             precision = CVT_DBL_BUF_SIZE-1;
  887.         } else if (precision == 0) {
  888.             precision = 1;
  889.         }
  890.  
  891. #if 0 /*def sun4*/
  892.          /*
  893.           * Varargs is not correctly implemented in gcc version 1.34
  894.           * for the sun4.  This problem should be fixed in the next
  895.           * version of the compiler, and this code can then be
  896.           * deleted.
  897.           */
  898.          {
  899.              union {
  900.                  long i[2];
  901.                  double d;
  902.              } u;
  903.  
  904.              u.i[0] = va_arg(args, long);
  905.              u.i[1] = va_arg(args, long);
  906.  
  907.              actualLength = CvtFtoA(u.d, precision,
  908.              -1, &point, &sign, &buf[1], &fpError);
  909.          }
  910. #else
  911.         actualLength = CvtFtoA(va_arg(args, double), precision,
  912.             -1, &point, &sign, &buf[1], &fpError);
  913.  
  914. #endif
  915.         if (fpError) {
  916.             break;
  917.         }
  918.         if (!altForm) {
  919.             for ( ; actualLength > 1; actualLength--) {
  920.             if (buf[actualLength] != '0') {
  921.                 break;
  922.             }
  923.             }
  924.         }
  925.         if ((actualLength > 1) || altForm) {
  926.             eLength = actualLength + 5;
  927.         } else {
  928.             eLength = actualLength + 4;
  929.         }
  930.         if (point <= 0) {
  931.             fLength = actualLength + 2 - point;
  932.         } else {
  933.             fLength = actualLength;
  934.             if (point < actualLength) {
  935.             fLength += 1;
  936.             } else if (altForm) {
  937.             fLength = point + 1;
  938.             } else {
  939.             fLength = point;
  940.             }
  941.         }
  942.  
  943.         /*
  944.          * Use "e" format if it results in fewer digits than "f"
  945.          * format, or if it would result in non-significant zeroes
  946.          * being printed.  Remember that precision means something
  947.          * different in "e" and "f" (digits after decimal) than it
  948.          * does in "g" (significant digits).
  949.          */
  950.  
  951.         if ((eLength < fLength) || (point > precision)) {
  952.             c += 'E' - 'G';
  953.             precision = actualLength-1;
  954.             goto eFromG;
  955.         }
  956.         c = 'f';
  957.         field = &buf[1];
  958.         actualLength = fLength;
  959.         if (sign) {
  960.             prefix = "-";
  961.             actualLength += 1;
  962.         }
  963.         break;
  964.         }
  965.  
  966.         case '%':
  967.         putc('%', stream);
  968.         charsPrinted += 1;
  969.         goto endOfField;
  970.  
  971.         case 0:
  972.         return charsPrinted;
  973.  
  974.         default:
  975.         putc(c, stream);
  976.         charsPrinted += 1;
  977.         goto endOfField;
  978.     }
  979.  
  980.     /* Handle pad characters on the left.  If the pad is '0', then
  981.      * padding goes after the prefix.  Otherwise, padding goes before
  982.      * the prefix.
  983.      */
  984.  
  985.     if (!leftAdjust) {
  986.         if (pad == '0') {
  987.         for ( ; *prefix != 0; prefix++) {
  988.             putc(*prefix, stream);
  989.             charsPrinted += 1;
  990.             actualLength--;
  991.             minWidth--;
  992.         }
  993.         }
  994.         while (minWidth > actualLength) {
  995.         putc(pad, stream);
  996.         charsPrinted += 1;
  997.         minWidth --;
  998.         }
  999.     }
  1000.  
  1001.     /*
  1002.      * Output anything left in the prefix.
  1003.      */
  1004.  
  1005.     minWidth -= actualLength;
  1006.     for ( ; *prefix != 0; prefix++) {
  1007.         putc(*prefix, stream);
  1008.         charsPrinted += 1;
  1009.         actualLength--;
  1010.     }
  1011.  
  1012.     /*
  1013.      * "F" and "f" formats are handled specially here:  output
  1014.      * everything up to and including the decimal point.
  1015.      */
  1016.  
  1017.     if (c == 'f' && !fpError) {
  1018.         if (point <= 0) {
  1019.         if (actualLength > 0) {
  1020.             putc('0', stream);
  1021.             charsPrinted += 1;
  1022.             point++;
  1023.             actualLength--;
  1024.         }
  1025.         if (actualLength > 0) {
  1026.             charsPrinted += 1;
  1027.             putc('.', stream);
  1028.             actualLength--;
  1029.         }
  1030.         while ((point <= 0) && (actualLength > 0)) {
  1031.             putc('0', stream);
  1032.             charsPrinted += 1;
  1033.             point++;
  1034.             actualLength--;
  1035.         }
  1036.         } else {
  1037.         while ((point > 0) && (actualLength > 0)) {
  1038.             putc(*field, stream);
  1039.             charsPrinted += 1;
  1040.             field++;
  1041.             point--;
  1042.             actualLength--;
  1043.         }
  1044.         if (actualLength > 0) {
  1045.             putc('.', stream);
  1046.             charsPrinted += 1;
  1047.             actualLength--;
  1048.         }
  1049.         }
  1050.     }
  1051.  
  1052.     /*
  1053.      * Output the contents of the field (for "f" format, this is
  1054.      * just the stuff after the decimal point).
  1055.      */
  1056.  
  1057.     charsPrinted += actualLength;
  1058.     for ( ; actualLength > 0; actualLength--, field++) {
  1059.         putc(*field, stream);
  1060.         }
  1061.  
  1062.     /*
  1063.      * Pad the right of the field, if necessary.
  1064.      */
  1065.  
  1066.     while (minWidth > 0) {
  1067.         putc(' ', stream);
  1068.         charsPrinted += 1;
  1069.         minWidth --;
  1070.     }
  1071.  
  1072.     endOfField: continue;
  1073.     }
  1074.     return charsPrinted;
  1075. }
  1076.  
  1077.  
  1078. /******************************************************************************
  1079.  *
  1080.  *        ALL THE OTHER PRINTF-RELATED FUNCTIONS
  1081.  *
  1082.  *****************************************************************************/
  1083.  
  1084.  
  1085. /***********************************************************************
  1086.  *                vprintf
  1087.  ***********************************************************************
  1088.  * SYNOPSIS:          Formatted output to stdout, given a varargs list
  1089.  * CALLED BY:        EXTERNAL
  1090.  * RETURN:        Number of characters placed in stdout.
  1091.  * SIDE EFFECTS:    Characters placed in stdout...of course
  1092.  *
  1093.  * STRATEGY:
  1094.  *
  1095.  * REVISION HISTORY:
  1096.  *    Name    Date        Description
  1097.  *    ----    ----        -----------
  1098.  *    ardeb    8/11/89        Initial Revision
  1099.  *
  1100.  ***********************************************************************/
  1101. int
  1102. vprintf(fmt, args)
  1103.     char    *fmt;
  1104.     va_list args;
  1105. {
  1106.     return(vfprintf(stdout, fmt, args));
  1107. }
  1108.  
  1109. /***********************************************************************
  1110.  *                vsprintf
  1111.  ***********************************************************************
  1112.  * SYNOPSIS:        Formatted output to a string, given a varargs list
  1113.  * CALLED BY:        EXTERNAL
  1114.  * RETURN:        Number of characters placed in string (not including null)
  1115.  * SIDE EFFECTS:    Characters are placed in the string
  1116.  *
  1117.  * STRATEGY:
  1118.  *
  1119.  * REVISION HISTORY:
  1120.  *    Name    Date        Description
  1121.  *    ----    ----        -----------
  1122.  *    ardeb    8/11/89        Initial Revision
  1123.  *
  1124.  ***********************************************************************/
  1125. int
  1126. vsprintf(str, fmt, args)
  1127.     char    *str;
  1128.     char    *fmt;
  1129.     va_list args;
  1130. {
  1131.     int            res;        /* Result of vfprintf */
  1132.     FILE        stream;        /* Temporary stream to string */
  1133.  
  1134.     /*
  1135.      * Set up a string stream with _cnt (space left in buffer) being
  1136.      * MAXINT, _base (base of buffer) and _ptr (current place in buffer) both
  1137.      * pointing to the string, and _flag marking the stream as a write-only,
  1138.      * string (so don't flush when full) stream.
  1139.      */
  1140.     stream._cnt = 0x7fffffff;
  1141.     stream._base = stream._ptr = (unsigned char *)str;
  1142.     stream._flag = _IOSTRG|_IOWRT;
  1143.     stream._file = -1;
  1144.  
  1145.     res = vfprintf(&stream, fmt, args);
  1146.  
  1147.     putc('\0', &stream);
  1148.  
  1149.     return(res);
  1150. }
  1151.  
  1152. /***********************************************************************
  1153.  *                printf
  1154.  ***********************************************************************
  1155.  * SYNOPSIS:        Formatted output to stdout...
  1156.  * CALLED BY:        EXTERNAL
  1157.  * RETURN:        Number of chars printed
  1158.  * SIDE EFFECTS:    Characters sent to stdout
  1159.  *
  1160.  * STRATEGY:
  1161.  *
  1162.  * REVISION HISTORY:
  1163.  *    Name    Date        Description
  1164.  *    ----    ----        -----------
  1165.  *    ardeb    8/11/89        Initial Revision
  1166.  *
  1167.  ***********************************************************************/
  1168. int
  1169. printf(fmt, va_alist)
  1170.     char    *fmt;
  1171.     va_dcl
  1172. {
  1173.     va_list    args;
  1174.     int            res;
  1175.  
  1176.     va_start(args);
  1177.  
  1178.     res = vfprintf(stdout, fmt, args);
  1179.  
  1180.     va_end(args);
  1181.  
  1182.     return(res);
  1183. }
  1184.     
  1185.     
  1186.  
  1187. /***********************************************************************
  1188.  *                fprintf
  1189.  ***********************************************************************
  1190.  * SYNOPSIS:        Formatted output to a stream
  1191.  * CALLED BY:        EXTERNAL
  1192.  * RETURN:        Number of chars printed
  1193.  * SIDE EFFECTS:    Characters sent to stream
  1194.  *
  1195.  * STRATEGY:
  1196.  *
  1197.  * REVISION HISTORY:
  1198.  *    Name    Date        Description
  1199.  *    ----    ----        -----------
  1200.  *    ardeb    8/11/89        Initial Revision
  1201.  *
  1202.  ***********************************************************************/
  1203. int
  1204. fprintf(stream, fmt, va_alist)
  1205.     FILE *stream;
  1206.     char *fmt;
  1207.     va_dcl
  1208. {
  1209.     va_list    args;
  1210.     int            res;
  1211.  
  1212.     va_start(args);
  1213.  
  1214.     res = vfprintf(stream, fmt, args);
  1215.  
  1216.     va_end(args);
  1217.  
  1218.     return(res);
  1219. }
  1220.     
  1221.  
  1222. /***********************************************************************
  1223.  *                sprintf
  1224.  ***********************************************************************
  1225.  * SYNOPSIS:        Formatted output to a string
  1226.  * CALLED BY:        EXTERNAL
  1227.  * RETURN:        Number of chars in string
  1228.  * SIDE EFFECTS:    Characters written into string (not including null)
  1229.  *
  1230.  * STRATEGY:
  1231.  *
  1232.  * REVISION HISTORY:
  1233.  *    Name    Date        Description
  1234.  *    ----    ----        -----------
  1235.  *    ardeb    8/11/89        Initial Revision
  1236.  *
  1237.  ***********************************************************************/
  1238. #if defined(is68k) || defined(vax)
  1239. char *
  1240. #else
  1241. int
  1242. #endif
  1243. sprintf(str, fmt, va_alist)
  1244.     char    *str;
  1245.     char        *fmt;
  1246.     va_dcl
  1247. {
  1248.     va_list     args;        /* List of passed args */
  1249.     int            res;        /* Result of vfprintf */
  1250.     FILE        stream;        /* Temporary stream to string */
  1251.  
  1252.     /*
  1253.      * Set up a string stream with _cnt (space left in buffer) being
  1254.      * MAXINT, _base (base of buffer) and _ptr (current place in buffer) both
  1255.      * pointing to the string, and _flag marking the stream as a write-only,
  1256.      * string (so don't flush when full) stream.
  1257.      */
  1258.     stream._cnt = 0x7fffffff;
  1259.     stream._base = stream._ptr = (unsigned char *)str;
  1260.     stream._flag = _IOSTRG|_IOWRT;
  1261.     stream._file = -1;
  1262.  
  1263.     va_start(args);
  1264.  
  1265.     res = vfprintf(&stream, fmt, args);
  1266.  
  1267.     /* Null-terminate */
  1268.     putc('\0', &stream);
  1269.     
  1270.     va_end(args);
  1271.  
  1272.     return(res);
  1273. }
  1274.  
  1275.  
  1276. /***********************************************************************
  1277.  *                snprintf
  1278.  ***********************************************************************
  1279.  * SYNOPSIS:        Formatted output to a string
  1280.  * CALLED BY:        EXTERNAL
  1281.  * RETURN:        Number of chars in string
  1282.  * SIDE EFFECTS:    Characters written into string (not including null)
  1283.  *
  1284.  * STRATEGY:
  1285.  *
  1286.  * REVISION HISTORY:
  1287.  *    Name    Date        Description
  1288.  *    ----    ----        -----------
  1289.  *    ardeb    8/11/89        Initial Revision
  1290.  *
  1291.  ***********************************************************************/
  1292. int
  1293. snprintf(str, len, fmt, va_alist)
  1294.     char    *str;
  1295.     int         len;
  1296.     char        *fmt;
  1297.     va_dcl
  1298. {
  1299.     va_list     args;        /* List of passed args */
  1300.     int            res;        /* Result of vfprintf */
  1301.     FILE        stream;        /* Temporary stream to string */
  1302.  
  1303.     /*
  1304.      * Set up a string stream with _cnt (space left in buffer) being
  1305.      * len-1 (to allow room for null), _base (base of buffer) and
  1306.      * _ptr (current place in buffer) both pointing to the string, and _flag
  1307.      * marking the stream as a write-only, string (so don't flush when full)
  1308.      * stream.
  1309.      */
  1310.     stream._cnt = len-1;
  1311.     stream._base = stream._ptr = (unsigned char *)str;
  1312.     stream._flag = _IOSTRG|_IOWRT;
  1313.     stream._file = -1;
  1314.  
  1315.     va_start(args);
  1316.  
  1317.     res = vfprintf(&stream, fmt, args);
  1318.  
  1319.     /*
  1320.      * Null-terminate, upping _cnt in case vfprintf filled up all the space
  1321.      * it was allowed to fill (lets us stick in the final null, for which
  1322.      * we saved room, above)
  1323.      */
  1324.     stream._cnt++;
  1325.     putc('\0', &stream);
  1326.     
  1327.     va_end(args);
  1328.  
  1329.     return(res);
  1330. }
  1331.  
  1332.